import logging

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,"_instance"):
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

class GlobalLog(Singleton):
    log_level_map = {
        "DEBUG" : logging.DEBUG,
        "INFO" : logging.INFO,
        "WARNING" : logging.WARNING,
        "ERROR" : logging.ERROR,
        "CRITICAL" : logging.CRITICAL
    }
    logger = None
    def __init__(self, *args, **kwargs):
        self.log_file_path = "/var/log/global_py_script.log"
        if "logpath" in kwargs:
            self.log_file_path = kwargs["logpath"]
        self.log_level = "DEBUG"
        if "loglevel" in kwargs:
            self.log_level = kwargs["loglevel"]
        new_logger = logging.getLogger(self.log_file_path)
        if self.logger is not new_logger:
            self.logger = new_logger
            self.logger.setLevel(self.log_level_map[self.log_level])
            fh = logging.FileHandler(self.log_file_path, mode='a')
            formatter = logging.Formatter("%(asctime)s - [pid:%(process)d][tid:%(thread)d] - %(levelname)s: %(message)s")
            fh.setFormatter(formatter)
            self.logger.addHandler(fh)
            # change current instance with new initialize
            self.set_current_ins(self)

    @classmethod
    def set_current_ins(cls, instance):
        cls._single_instance = instance

    @classmethod
    def get_current_ins(cls):
        if not hasattr(cls, "_single_instance"):
            cls._single_instance = cls()
        return cls._single_instance

    def debug(self, *args):
        self.logger.debug(' '.join(map(lambda e:str(e), args)))

    def info(self, *args):
        self.logger.info(' '.join(map(lambda e:str(e), args)))

    def warn(self, *args):
        self.logger.warning(' '.join(map(lambda e:str(e), args)))

    def error(self, *args):
        self.logger.error(' '.join(map(lambda e:str(e), args)))

    def critical(self, *args):
        self.logger.critical(' '.join(map(lambda e:str(e), args)))

def init(*args, **kwargs):
    gl = GlobalLog(*args, **kwargs)

def default_init(func):
    def wrapper(*args):
        gl = GlobalLog.get_current_ins()
        func(*args, gl=gl)
    return wrapper

@default_init
def debug(*args, **kwargs):
    gl = kwargs['gl']
    if gl:
        gl.debug(*args)

@default_init
def info(*args, **kwargs):
    gl = kwargs['gl']
    if gl:
        gl.info(*args)

@default_init
def warn(*args, **kwargs):
    gl = kwargs['gl']
    if gl:
        gl.warn(*args)

@default_init
def error(*args, **kwargs):
    gl = kwargs['gl']
    if gl:
        gl.error(*args)

@default_init
def critical(*args, **kwargs):
    gl = kwargs['gl']
    if gl:
        gl.critical(*args)
